package com.study.spmongodb.book.wwj.char15;

import java.util.concurrent.TimeUnit;

/**
 * @author MI
 * @version 1.0
 * @date 2020/11/28 10:51
 */
public class ObservableThread<T> extends Thread implements Observable {

    private final TaskLifecycle<T> lifecycle;
    private final Task<T> task;

    private Cycle cycle;

    //指定task的实现，默认情况下使用Emptylifecycle
    public ObservableThread(Task<T> task) throws IllegalAccessException {
        this(new TaskLifecycle.EmptyLifecycle<T>(), task);
    }

    public ObservableThread(TaskLifecycle<T> lifecycle, Task<T> task) throws IllegalAccessException {
        super();
        if (task == null) {
            throw new IllegalAccessException("the task is required");
        }
        this.lifecycle = lifecycle;
        this.task = task;

    }

    @Override
    public void run() {
        //在执行线程逻辑单元的时候，分别触发相应的事件
        this.update(Cycle.STARTED, null, null);
        try {
            this.update(Cycle.RUNNING, null, null);
            final T result = this.task.call();
            this.update(Cycle.DONE, result, null);
        } catch (Exception e) {
            this.update(Cycle.ERROR, null, e);
        }

    }

    public void update(Cycle cycle, T result, Exception e) {
        this.cycle = cycle;
        if (lifecycle == null) {
            return;
        }
        try {
            switch (cycle) {
                case STARTED:
                    this.lifecycle.onStart(currentThread());
                    break;
                case RUNNING:
                    this.lifecycle.onRunning(currentThread());
                    break;
                case DONE:
                    this.lifecycle.onFinish(currentThread(), result);
                    break;
                case ERROR:
                    this.lifecycle.onError(currentThread(), e);
                    break;

            }
        } catch (Exception exception) {
            if (cycle == Cycle.ERROR) {
                throw exception;
            }
        }
    }

    @Override
    public Cycle getCycle() {
        return this.cycle;
    }

    public static void main(String[] args) throws IllegalAccessException {
        final ObservableThread observableThread = new ObservableThread<>(() -> {
            try {
                TimeUnit.SECONDS.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        });

        observableThread.start();
    }
}
